package mypack;

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Reducer;

public class EvolutionReducer  extends Reducer <IntWritable, Chromosome, IntWritable, Chromosome>
{
	static enum MY_COUNTERS
	{
		GENERATION_NUMBER
	};
	
	public void reduce(IntWritable key, Iterable<Chromosome> values, Context context ) throws IOException, InterruptedException 
	{
		Population population = new Population();

		//Global.gen.readFile();
		Global.gen.readTSPLIBFile();
		int index = 0;
		for (Chromosome value : values)
		{
			//System.out.println("reducer key - fitness: "+key+" - "+value.mFitness);
			if (index >= population.currentPopulation.length)
				break;
			population.currentPopulation[index] = value.copyChromosome();
			index++;
			//population.calculateAllPathLengths();
		}
		
		
		int generationNumber = population.currentPopulation[0].generationNumber+1;
		
/*		//for debugging
		int writeID = generationNumber + 100;
		
		population.calculateAllPathLengths();
		
		population.printPopulation(writeID, population.currentPopulation[0].populationId);
		
		//end of debugging
*/		
		int counter = 1000;
		context.getCounter(MY_COUNTERS.GENERATION_NUMBER).increment((generationNumber-1)*counter);
		while (counter != 0 && !population.isGoodEnough()) 
		{
			context.getCounter(MY_COUNTERS.GENERATION_NUMBER).increment(1);
			//int generationNum = (int)context.getCounter(MY_COUNTERS.GENERATION_NUMBER).getValue();
			for (int i = 0; i < Global.POPULATION_SIZE-1; i=i+2) 
			{
				//int mate1 = population.select();
				//int mate2 = population.select();
				
				int mate1 = population.rankSelect();
				Chromosome c1 = population.currentPopulation[mate1];
				Chromosome c2 = null;
				int mate2 = mate1;
				int counter2 = 0;
				do {
					mate2 = population.rankSelect();
					//mate2 = population.select();
					c2 = population.currentPopulation[mate2];
					counter2++;
				//} while (c1.isSame(c2));
				} while (c1.similarityPercentage(c2) > 70 && counter2 < Global.POPULATION_SIZE); // benzerlik %80'dan fazla oldugu surece

				population.currentPopulation[mate1].numberOfChosen++;
				population.currentPopulation[mate2].numberOfChosen++;

				Newbies children=null;
				
//				if (mate1 <  0 || mate2 < 0) 
//				{
//					int id = generationNum+i;
//					Population.writeLog("mateSelect",""+id,"mate1: "+mate1+" mate2: "+mate2);
//				}
//				else
				
					children = population.crossover_2(mate1, mate2); //crossover and mutation
				
				
				//children.child1.orderInPopulation = i;
				//children.child2.orderInPopulation = i+1;
				children.child1.populationId = population.currentPopulation[0].populationId;
				children.child2.populationId = population.currentPopulation[0].populationId;
				children.child1.prevPop = population.currentPopulation[0].populationId;
				children.child2.prevPop = population.currentPopulation[0].populationId;
//				children.child1.generationNumber = population.currentPopulation[0].generationNumber+1;
//				children.child2.generationNumber = population.currentPopulation[0].generationNumber+1;
				population.newPopulation[i] = children.child1.copyChromosome();
				population.newPopulation[i+1] = children.child2.copyChromosome();
			}
			
			//population.printPopulation(generationNumber ,population.currentPopulation[0].populationId);
			
			int numOfBestTransfer = 1;//Global.POPULATION_SIZE * 5 / 100;
			population.mutationNewPop();
			population.calculateNewPopPathLengths();
			for (int i = 0; i < numOfBestTransfer; i++) 
			{
				population.newPopulation[Global.POPULATION_SIZE-i-1] = population.currentPopulation[i].copyChromosome();
			}
			
			population.copyNewPopToCurrentPop();
			//population.mutation();
			population.calculateAllPathLengths();
			counter--;
		
		}

		for (int i = 0; i < Global.POPULATION_SIZE - (Global.EXCHANGE_NUM * (Global.MAPREDUCE_NUMBER -1)); i++) 
		{
			Chromosome valueToWrite = population.currentPopulation[i];
			valueToWrite.generationNumber = generationNumber;
			valueToWrite.prevPop = valueToWrite.populationId;
			IntWritable keyToWrite = new IntWritable(valueToWrite.populationId);
			context.write(keyToWrite,valueToWrite);
		}
		
		//the best 2 chromosome sent to the other populations
		Chromosome list [] = population.getTopTenChromosomes();
		
		if (list[Global.EXCHANGE_NUM-1] != null) 
		{
			//Population.writeLog("exhange", ""+list[0].generationNumber+"_"+list[0].populationId, ""+list.length);
			for (int i = 0; i < Global.EXCHANGE_NUM; i++) 
			{		
				Chromosome valueToWrite = list[i].copyChromosome();
				valueToWrite.generationNumber = generationNumber;
				for (int j = 0; j < Global.MAPREDUCE_NUMBER-1; j++) 
				{
					int key_1 = ((valueToWrite.populationId+j) % Global.MAPREDUCE_NUMBER) + 1 ; //population id : 1 to 4
					valueToWrite.prevPop = valueToWrite.populationId;
					valueToWrite.populationId = key_1;
					IntWritable keyToWrite = new IntWritable(key_1);
					context.write(keyToWrite,valueToWrite);
				}
			}
		}
		population.writeBestOneToHDFS(generationNumber ,population.currentPopulation[0].populationId);
		
		System.out.println("*******************************");
	}

}
